﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Runtime.InteropServices;
using Un4seen.Bass;
using Un4seen.Bass.AddOn.Fx;
using Un4seen.Bass.Misc;

namespace EditorDeAudioTT201095
{
    public partial class ArchivosAudio : Form
    {
        public ArchivosAudio()
        {
            InitializeComponent();
        }

        private int flujo = 0;
        private int flujoEfectos = 0;
        private string nombreArchivo = String.Empty;
        private int contadorMarca = 0;
        private bool espectroCompleto = true;
        private Un4seen.Bass.BASSTimer actualizarReloj = null;
        private int latenciaDispositivoBytes = 0; 
        private int _updateInterval = 50; // 50ms
        private Visuals modificadorVisual = new Visuals();
        private SYNCPROC _sync = null;
        private DSP_Gain ganancia;
        private int _syncer = 0;
        private int contadorInstante = 0;
        private int[] ecualizador = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        private int prioridadModerador = 9;
        private BASS_BFX_DAMP moderador = new BASS_BFX_DAMP();

        private void CargarEfectos(object sender, System.EventArgs e)
        {
            if (Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_SPEAKERS, this.Handle))
            {
                // Parámetros correctos, carga BASS_FX
                BassFx.BASS_FX_GetVersion();
                moderador.Preset_Medium();

                actualizarReloj = new Un4seen.Bass.BASSTimer(_updateInterval);
                actualizarReloj.Tick += new EventHandler(timerUpdate_Tick);

                _sync = new SYNCPROC(SetPosition);

                modificadorVisual.MaxFFT = BASSData.BASS_DATA_FFT1024;
                modificadorVisual.MaxFrequencySpectrum = Utils.FFTFrequency2Index(16000, 1024, 44100);
            }
        }

        private void CerrarEfectos(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Bass.BASS_Stop();
            Bass.BASS_Free();
        }

        private int longitud20ms = 0;
        private float[] _rmsData; // buffer global de datos en RMS
        private double valorCuadráticoMediio(int canal, out int picoIzquierdo, out int picoDerecho)
        {
            double suma = 0f;
            float valorMaximoIzquierdo = 0f;
            float valorMaximoDerecho = 0f;
            int longitud = longitud20ms;
            int l4 = longitud / 4; // cantidad de numeros con precisión de 32-bit requeridos (longitud en bytes)

            // incrementa el buffer de datos como se necesite
            if (_rmsData == null || _rmsData.Length < l4)
                _rmsData = new float[l4];

            try
            {
                longitud = Bass.BASS_ChannelGetData(canal, _rmsData, longitud);
                l4 = longitud / 4;

                for (int a = 0; a < l4; a++)
                {
                    suma += _rmsData[a] * _rmsData[a]; // suma de cuadrados
                    // Elige canal derecho/izquierdo
                    if (a % 2 == 0)
                    {
                        // Canal izquierdo
                        if (_rmsData[a] > valorMaximoIzquierdo)
                            valorMaximoIzquierdo = _rmsData[a];
                    }
                    else
                    {
                        // Canal derecho
                        if (_rmsData[a] > valorMaximoDerecho)
                            valorMaximoDerecho = _rmsData[a];
                    }
                }
            }
            catch { }

            picoIzquierdo = (int)Math.Round(32768f * valorMaximoIzquierdo);
            if (picoIzquierdo > 32768)
                picoIzquierdo = 32768;
            picoDerecho = (int)Math.Round(32768f * valorMaximoDerecho);
            if (picoDerecho > 32768)
                picoDerecho = 32768;

            return Math.Sqrt(suma / (l4 / 2)); // por ser dos canales
        }

        private void timerUpdate_Tick(object sender, System.EventArgs e)
        {
            if (Bass.BASS_ChannelIsActive(flujoEfectos) == BASSActive.BASS_ACTIVE_PLAYING)
            {
                // Continúa reproduciendo el flujo
            }
            else
            {
                // El flujo ya no se reproduce
                this.timerUpdate.Stop();
                this.progressBarPeakLeft.Value = 0;
                this.progressBarPeakRight.Value = 0;
                this.labelContador.Text = "Reproducción Detenida";
                return;
            }
            contadorInstante++;
            long pos = Bass.BASS_ChannelGetPosition(flujo); // posición in bytes
            long len = Bass.BASS_ChannelGetLength(flujo); // longitud in bytes

            if (contadorInstante % 5 == 0)
            {                
                this.Text = String.Format("CPU: {0:0.00}%", Bass.BASS_GetCPU());
            }

            // Actualiza la posición de la onda
            DrawWavePosition(pos, len);
            if (espectroCompleto)
                this.pictureBoxSpectrum.Image = modificadorVisual.CreateSpectrumLinePeak(flujoEfectos, this.pictureBoxSpectrum.Width, this.pictureBoxSpectrum.Height, Color.Wheat, Color.Gold, Color.DarkOrange, Color.Black, 2, 1, 1, 13, false, true, false);
            else
                this.pictureBoxSpectrum.Image = modificadorVisual.CreateWaveForm(flujoEfectos, this.pictureBoxSpectrum.Width, this.pictureBoxSpectrum.Height, Color.Green, Color.Red, Color.Gray, Color.Linen, 1, true, false, true);

            int picoIzquierdo = 0;
            int picoDerecho = 0;
            double rms = valorCuadráticoMediio(flujoEfectos, out picoIzquierdo, out picoDerecho);
            this.progressBarPeakLeft.Value = picoIzquierdo;
            this.progressBarPeakRight.Value = picoDerecho;

            contadorMarca++;
            if (contadorMarca == 4)
            {
                contadorMarca = 0;
                long leng = Bass.BASS_ChannelGetLength(flujoEfectos); // longitud en bytes
                long posit = Bass.BASS_ChannelGetPosition(flujoEfectos); // posición in bytes
                double tiempoTotal = Bass.BASS_ChannelBytes2Seconds(flujoEfectos, leng); // Tiempo de duracion total
                double tiempoTranscurrido = Bass.BASS_ChannelBytes2Seconds(flujoEfectos, posit); // Tiempo transcurrido
                double remainingtime = tiempoTotal - tiempoTranscurrido;
                this.labelContador.Text = String.Format("Transcurrido: {0} - Total: {1} - Restante: {2}", Utils.FixTimespan(tiempoTranscurrido, "MMSS"), Utils.FixTimespan(tiempoTotal, "MMSS"), Utils.FixTimespan(remainingtime, "MMSS"));

                this.labelRMSValue.Text = Utils.LevelToDB(rms, 1d).ToString("0.0");
            }
        }

        private void buttonPlay_Click(object sender, System.EventArgs e)
        {
            this.checkBoxFlanger.Checked = false;
            this.checkBoxEcho.Checked = false;
            Bass.BASS_StreamFree(flujoEfectos);
            if (nombreArchivo != String.Empty)
            {
                // crea un flujo de decodificación
                flujo = Bass.BASS_StreamCreateFile(nombreArchivo, 0, 0, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_PRESCAN);
                if (flujo != 0)
                {
                    longitud20ms = (int)Bass.BASS_ChannelSeconds2Bytes(flujo, 0.02f); // Ventana de 20ms 
                    bpmProc = new BPMPROCESSPROC(MyBPMProc);
                    float bpm = BassFx.BASS_FX_BPM_DecodeGet(flujo, 1f, 180f, Utils.MakeLong(50, 180), BASSFXBpm.BASS_FX_BPM_BKGRND | BASSFXBpm.BASS_FX_FREESOURCE | BASSFXBpm.BASS_FX_BPM_MULT2, bpmProc);
                    
                    ganancia = new DSP_Gain(flujo, 0);
                    buttonEstablecerGanancia_Click(this, EventArgs.Empty);
                    trackBarGanancia_ValueChanged_1(this, EventArgs.Empty);
                                        Bass.BASS_ChannelSetPosition(flujo, 0);
                    // EQ-Ecualizador de 10 bandas
                    BASS_DX8_PARAMEQ eq = new BASS_DX8_PARAMEQ();
                    ecualizador[0] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    ecualizador[1] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    ecualizador[2] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    ecualizador[3] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    ecualizador[4] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    ecualizador[5] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    ecualizador[6] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    ecualizador[7] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    ecualizador[8] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);
                    ecualizador[9] = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_DX8_PARAMEQ, 0);

                    eq.fBandwidth = 18f;

                    eq.fCenter = 31f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(ecualizador[0], eq);

                    eq.fCenter = 63f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(ecualizador[1], eq);

                    eq.fCenter = 125f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(ecualizador[2], eq);

                    eq.fCenter = 250f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(ecualizador[3], eq);

                    eq.fCenter = 500f;
                    eq.fGain = this.trackBarEQBanda63.Value / 10f;
                    Bass.BASS_FXSetParameters(ecualizador[4], eq);

                    eq.fCenter = 1000f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(ecualizador[5], eq);

                    eq.fCenter = 2000f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(ecualizador[6], eq);

                    eq.fCenter = 4000f;
                    eq.fGain = this.trackBarEQBanda31.Value / 10f;
                    Bass.BASS_FXSetParameters(ecualizador[7], eq);

                    eq.fCenter = 8000f;
                    eq.fGain = this.trackBarEQBanda125.Value / 10f;
                    Bass.BASS_FXSetParameters(ecualizador[8], eq);

                    eq.fCenter = 16000f;
                    eq.fGain = this.trackBarEQBanda125.Value / 10f;
                    Bass.BASS_FXSetParameters(ecualizador[9], eq);
                    flujoEfectos = BassFx.BASS_FX_TempoCreate(flujo, BASSFlag.BASS_FX_FREESOURCE | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_SAMPLE_LOOP);
                }

                if (flujoEfectos != 0 && Bass.BASS_ChannelPlay(flujoEfectos, false))
                {
                    GetWaveForm();
                    this.timerUpdate.Start();
                    this.buttonDetener.Enabled = true;
                    this.buttonReproducir.Enabled = false;

                    beatProc = new BPMBEATPROC(MyBeatProc);
                    BassFx.BASS_FX_BPM_BeatCallbackSet(flujoEfectos, beatProc, IntPtr.Zero);
                }
                else
                {
                    Console.WriteLine("Error = {0}", Bass.BASS_ErrorGetCode());
                }
            }
        }

        private BPMPROCESSPROC bpmProc;
        private void MyBPMProc(int chan, float percent)
        {
            BeginInvoke((MethodInvoker)delegate()
            {});
        }

        private BPMBEATPROC beatProc;
        private void MyBeatProc(int handle, double beatpos, IntPtr user)
        {
            BeginInvoke((MethodInvoker)delegate()
            {});
        }

        private void buttonPausar_Click(object sender, EventArgs e)
        {
            if (Bass.BASS_ChannelIsActive(flujo) == BASSActive.BASS_ACTIVE_PLAYING)
            {
                Bass.BASS_ChannelPause(flujo);
            }
            else
            {
                Bass.BASS_ChannelPlay(flujo, false);
            }
        }

        private void buttonDetener_Click(object sender, EventArgs e)
        {
            DetenerFlujo();
        }

        private void DetenerFlujo()
        {
            timerUpdate.Stop();
            if (FormaDeOnda != null && FormaDeOnda.IsRenderingInProgress)
                FormaDeOnda.RenderStop();
            DrawWavePosition(-1, -1);

            Bass.BASS_StreamFree(flujo);
            flujo = 0;
            this.labelContador.Text = "Detenido";
            this.buttonSeleccionArchivo.Text = "Abrir";
            this.buttonDetener.Enabled = false;
            this.buttonReproducir.Enabled = true;
        }

        private void buttonAbrir_Click(object sender, System.EventArgs e)
        {
            this.openFileDialog.FileName = nombreArchivo;
            if (DialogResult.OK == this.openFileDialog.ShowDialog(this))
            {
                if (File.Exists(this.openFileDialog.FileName))
                {
                    nombreArchivo = this.openFileDialog.FileName;
                    this.buttonSeleccionArchivo.Text = Path.GetFileName(nombreArchivo);
                }
                else
                    nombreArchivo = String.Empty;
            }
        }

        private int _flangerFX = 0;
        private void checkBoxFlanger_CheckedChanged(object sender, System.EventArgs e)
        {
            if (flujoEfectos == 0)
                return;

            if (this.checkBoxFlanger.Checked)
            {
                _flangerFX = Bass.BASS_ChannelSetFX(flujoEfectos, BASSFXType.BASS_FX_BFX_FLANGER, -4);
                BASS_BFX_FLANGER flanger = new BASS_BFX_FLANGER();
                flanger.Preset_Default();
                Bass.BASS_FXSetParameters(_flangerFX, flanger);

                BASS_BFX_FLANGER f = new BASS_BFX_FLANGER();
                Bass.BASS_FXGetParameters(_flangerFX, f);
            }
            else
            {
                Bass.BASS_ChannelRemoveFX(flujoEfectos, _flangerFX);
                _flangerFX = 0;
            }
        }

        private void buttonFlangerApply_Click(object sender, System.EventArgs e)
        {
            if (flujoEfectos == 0)
                return;

            BASS_BFX_FLANGER flanger = new BASS_BFX_FLANGER();
            
            Bass.BASS_FXGetParameters(_flangerFX, flanger);
            flanger.fSpeed = float.Parse(this.textBoxFlangerSpeed.Text);
            
            Bass.BASS_FXSetParameters(_flangerFX, flanger);
        }

        private int _echoFX = 0;
        private void checkBoxEcho_CheckedChanged(object sender, System.EventArgs e)
        {
            if (flujoEfectos == 0)
                return;

            if (this.checkBoxEcho.Checked)
            {
                _echoFX = Bass.BASS_ChannelSetFX(flujoEfectos, BASSFXType.BASS_FX_BFX_ECHO3, -3);
                BASS_BFX_ECHO3 echo = new BASS_BFX_ECHO3();
                echo.Preset_LongEcho();
                Bass.BASS_FXSetParameters(_echoFX, echo);
            }
            else
            {
                Bass.BASS_ChannelRemoveFX(flujoEfectos, _echoFX);
                _echoFX = 0;
            }
        }

        private void buttonEchoApply_Click(object sender, System.EventArgs e)
        {
            if (flujoEfectos == 0)
                return;

            BASS_BFX_ECHO3 echo = new BASS_BFX_ECHO3();
            Bass.BASS_FXGetParameters(_echoFX, echo);
            echo.fDelay = float.Parse(this.textBoxEchoDelay.Text);
            Bass.BASS_FXSetParameters(_echoFX, echo);
        }

        private int efectoReverb = 0;
        private void checkBoxReverb_CheckedChanged(object sender, EventArgs e)
        {
            if (flujoEfectos == 0)
                return;

            if (this.checkBoxReverb.Checked)
            {
                efectoReverb = Bass.BASS_ChannelSetFX(flujoEfectos, BASSFXType.BASS_FX_BFX_REVERB, -3);
                BASS_BFX_REVERB reverb = new BASS_BFX_REVERB();
                reverb.fLevel = 0.5f;
                Bass.BASS_FXSetParameters(efectoReverb, reverb);
            }
            else
            {
                Bass.BASS_ChannelRemoveFX(flujoEfectos, efectoReverb);
                efectoReverb = 0;
            }
        }

        private void buttonAplicarReverb_Click(object sender, EventArgs e)
        {
            if (flujoEfectos == 0)
                return;

            BASS_BFX_REVERB reverb = new BASS_BFX_REVERB();
            Bass.BASS_FXGetParameters(efectoReverb, reverb);
            reverb.lDelay = int.Parse(this.textBoxRetrasoReverb.Text);
            Bass.BASS_FXSetParameters(efectoReverb, reverb);
        }

        private void trackBarSpeed_Scroll(object sender, System.EventArgs e)
        {
            Bass.BASS_ChannelSetAttribute(flujoEfectos, BASSAttribute.BASS_ATTRIB_TEMPO_FREQ, (float)trackBarVelReprod.Value);

            float ratio = BassFx.BASS_FX_TempoGetRateRatio(flujoEfectos);
            this.labelRatio.Text = String.Format("{0}", ratio);
        }

        private void buttonSpeedreset_Click(object sender, System.EventArgs e)
        {
            trackBarVelReprod.Value = 44100;
            Bass.BASS_ChannelSetAttribute(flujoEfectos, BASSAttribute.BASS_ATTRIB_TEMPO_FREQ, (float)trackBarVelReprod.Value);
            this.labelRatio.Text = "";
        }

        private void pictureBoxSpectrum_Click(object sender, EventArgs e)
        {
            espectroCompleto = !espectroCompleto;
        }

        private void ActualizarEQ(int band, float gain)
        {
            BASS_DX8_PARAMEQ eq = new BASS_DX8_PARAMEQ();
            if (Bass.BASS_FXGetParameters(ecualizador[band], eq))
            {
                eq.fGain = gain;
                Bass.BASS_FXSetParameters(ecualizador[band], eq);
            }
        }

        private void trackBarEQBanda31_ValueChanged(object sender, EventArgs e)
        {
            ActualizarEQ(0, trackBarEQBanda31.Value / 10f);
        }

        private void trackBarEQBanda63_ValueChanged(object sender, EventArgs e)
        {
            ActualizarEQ(1, trackBarEQBanda63.Value / 10f);
        }

        private void trackBarEQBanda125_ValueChanged(object sender, EventArgs e)
        {
            ActualizarEQ(2, trackBarEQBanda125.Value / 10f);
        }

        private void trackBarEQBanda250_ValueChanged(object sender, EventArgs e)
        {
            ActualizarEQ(3, trackBarEQBanda250.Value / 10f);
        }

        private void trackBarEQBanda500_ValueChanged(object sender, EventArgs e)
        {
             ActualizarEQ(4, trackBarEQBanda500.Value / 10f);
        }

        private void trackBarEQBanda1000_ValueChanged(object sender, EventArgs e)
        {
            ActualizarEQ(5, trackBarEQBanda1000.Value / 10f);
        }

        private void trackBarEQBanda2000_ValueChanged(object sender, EventArgs e)
        {
            ActualizarEQ(6, trackBarEQBanda2000.Value / 10f);
        }

        private void trackBarEQBanda4000_ValueChanged(object sender, EventArgs e)
        {
            ActualizarEQ(7, trackBarEQBanda4000.Value / 10f);
        }

        private void trackBarEQBanda8000_ValueChanged(object sender, EventArgs e)
        {
            ActualizarEQ(8, trackBarEQBanda8000.Value / 10f);
        }

        private void trackBarEQBanda16000_ValueChanged(object sender, EventArgs e)
        {
            ActualizarEQ(9, trackBarEQBanda16000.Value / 10f);
        }

        private bool _zoomed = false;
        private int _zoomStart = -1;
        private long _zoomStartBytes = -1;
        private int _zoomEnd = -1;
        private float _zoomDistance = 5.0f; 

        private Un4seen.Bass.Misc.WaveForm FormaDeOnda = null;
        private void GetWaveForm()
        {
            FormaDeOnda = new WaveForm(this.nombreArchivo, new WAVEFORMPROC(MyWaveFormCallback), this);
            FormaDeOnda.FrameResolution = 0.005f;
            FormaDeOnda.CallbackFrequency = 4000;
            FormaDeOnda.ColorBackground = SystemColors.Control;
            FormaDeOnda.ColorLeft = Color.Gainsboro;
            FormaDeOnda.ColorLeftEnvelope = Color.Gray;
            FormaDeOnda.ColorRight = Color.LightGray;
            FormaDeOnda.ColorRightEnvelope = Color.DimGray;
            FormaDeOnda.ColorMarker = Color.DarkBlue;
            FormaDeOnda.DrawWaveForm = WaveForm.WAVEFORMDRAWTYPE.Stereo;
            FormaDeOnda.DrawMarker = WaveForm.MARKERDRAWTYPE.Line | WaveForm.MARKERDRAWTYPE.Name | WaveForm.MARKERDRAWTYPE.NamePositionAlternate;
            FormaDeOnda.RenderStart(true, BASSFlag.BASS_DEFAULT);
            FormaDeOnda.SyncPlayback(flujo);
        }

        private void MyWaveFormCallback(int framesDone, int framesTotal, TimeSpan elapsedTime, bool finished)
        {
            DrawWave();
            if (finished)
            {
                Console.WriteLine("Trazado en {0}sec.", elapsedTime);
                Console.WriteLine("Marcos Trazados={0} de {1}", FormaDeOnda.FramesRendered, FormaDeOnda.FramesToRender);
            }
        }

        private void pictureBox1_Resize(object sender, System.EventArgs e)
        {
            DrawWave();
        }

        private void DrawWave()
        {
            if (FormaDeOnda != null)
                this.pictureBox1.BackgroundImage = FormaDeOnda.CreateBitmap(this.pictureBox1.Width, this.pictureBox1.Height, _zoomStart, _zoomEnd, true);
            else
                this.pictureBox1.BackgroundImage = null;
        }

        private void DrawWavePosition(long pos, long len)
        {
            if (len == 0 || pos < 0)
            {
                this.pictureBox1.Image = null;
                return;
            }

            Bitmap bitmap = null;
            Graphics g = null;
            Pen p = null;
            double bpp = 0;

            try
            {
                if (_zoomed)
                {

                    len = FormaDeOnda.Frame2Bytes(_zoomEnd) - _zoomStartBytes;

                    int scrollOffset = 1;
                    if (pos > (_zoomStartBytes + len - scrollOffset * FormaDeOnda.Wave.bpf))
                    {
                        _zoomStart = FormaDeOnda.Position2Frames(pos - scrollOffset * FormaDeOnda.Wave.bpf);
                        _zoomStartBytes = FormaDeOnda.Frame2Bytes(_zoomStart);
                        _zoomEnd = _zoomStart + FormaDeOnda.Position2Frames(_zoomDistance) - 1;
                        if (_zoomEnd >= FormaDeOnda.Wave.data.Length)
                        {
                            _zoomEnd = FormaDeOnda.Wave.data.Length - 1;
                            _zoomStart = _zoomEnd - FormaDeOnda.Position2Frames(_zoomDistance) + 1;
                            if (_zoomStart < 0)
                                _zoomStart = 0;
                            _zoomStartBytes = FormaDeOnda.Frame2Bytes(_zoomStart);
                            len = FormaDeOnda.Frame2Bytes(_zoomEnd) - _zoomStartBytes;
                        }
                        DrawWave();
                    }
                    pos -= _zoomStartBytes; 

                    bpp = len / (double)this.pictureBox1.Width; 
                }
                else
                {
                    bpp = len / (double)this.pictureBox1.Width;
                }

                pos -= latenciaDispositivoBytes;

                p = new Pen(Color.Red);
                bitmap = new Bitmap(this.pictureBox1.Width, this.pictureBox1.Height);
                g = Graphics.FromImage(bitmap);
                g.Clear(Color.White);
                int x = (int)Math.Round(pos / bpp);  
                g.DrawLine(p, x, 0, x, this.pictureBox1.Height - 1);
                bitmap.MakeTransparent(Color.White);
            }
            catch
            {
                bitmap = null;
            }
            finally
            {
                if (p != null)
                    p.Dispose();
                if (g != null)
                    g.Dispose();
            }

            this.pictureBox1.Image = bitmap;
        }

        private void buttonZoom_Click(object sender, System.EventArgs e)
        {
            if (FormaDeOnda == null)
                return;

            if (_zoomed)
            {
                _zoomStart = -1;
                _zoomStartBytes = -1;
                _zoomEnd = -1;
                _zoomDistance = 5.0f;
            }
            else
            {
                long pos = Bass.BASS_ChannelGetPosition(this.flujo);
                _zoomStart = FormaDeOnda.Position2Frames(pos);
                _zoomStartBytes = FormaDeOnda.Frame2Bytes(_zoomStart);
                _zoomEnd = _zoomStart + FormaDeOnda.Position2Frames(_zoomDistance) - 1;
                if (_zoomEnd >= FormaDeOnda.Wave.data.Length)
                {
                    _zoomEnd = FormaDeOnda.Wave.data.Length - 1;
                    _zoomStart = _zoomEnd - FormaDeOnda.Position2Frames(_zoomDistance) + 1;
                    _zoomStartBytes = FormaDeOnda.Frame2Bytes(_zoomStart);
                }
            }
            _zoomed = !_zoomed;
            DrawWave();
        }

        private void pictureBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (FormaDeOnda == null)
                return;

            if (e.Button == MouseButtons.Left)
            {
                long pos = FormaDeOnda.GetBytePositionFromX(e.X, this.pictureBox1.Width, _zoomStart, _zoomEnd);
                FormaDeOnda.AddMarker("INICIO", pos);
                Bass.BASS_ChannelSetPosition(flujo, pos);
                if (FormaDeOnda.Wave.marker.ContainsKey("FIN"))
                {
                    long endpos = FormaDeOnda.Wave.marker["FIN"];
                    if (endpos < pos)
                    {
                        FormaDeOnda.RemoveMarker("FIN");
                    }
                }
                DrawWave();
            }
            else if (e.Button == MouseButtons.Right)
            {
                long pos = FormaDeOnda.GetBytePositionFromX(e.X, this.pictureBox1.Width, _zoomStart, _zoomEnd);
                FormaDeOnda.AddMarker("FIN", pos);
                Bass.BASS_ChannelRemoveSync(flujo, _syncer);
                _syncer = Bass.BASS_ChannelSetSync(flujo, BASSSync.BASS_SYNC_POS, pos, _sync, IntPtr.Zero);
                if (FormaDeOnda.Wave.marker.ContainsKey("INCIO"))
                {
                    long startpos = FormaDeOnda.Wave.marker["INICIO"];
                    if (startpos > pos)
                    {
                        FormaDeOnda.RemoveMarker("INICIO");
                    }
                }
                DrawWave();
            }
        }

        private void SetPosition(int handle, int channel, int data, IntPtr user)
        {
            if (FormaDeOnda.Wave.marker.ContainsKey("INICIO"))
            {
                long startpos = FormaDeOnda.Wave.marker["INICIO"];
                Bass.BASS_ChannelSetPosition(flujo, (long)startpos);
                if (_zoomed)
                {
                    _zoomStart = FormaDeOnda.Position2Frames((long)startpos) - 1;
                    _zoomStartBytes = FormaDeOnda.Frame2Bytes(_zoomStart);
                    if (FormaDeOnda.Wave.marker.ContainsKey("FIN"))
                    {
                        long endpos = FormaDeOnda.Wave.marker["FIN"];
                        _zoomEnd = FormaDeOnda.Position2Frames((long)endpos) + 10;
                        _zoomDistance = FormaDeOnda.Frame2Bytes(_zoomEnd) - FormaDeOnda.Frame2Bytes(_zoomStart);
                    }
                    DrawWave();
                }
            }
            else
                Bass.BASS_ChannelSetPosition(flujo, 0);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            Microfono manejoMicrofono = new Microfono();
            this.Hide();
            manejoMicrofono.ShowDialog();
        }

        private void buttonEstablecerGanancia_Click(object sender, EventArgs e)
        {
            if (ganancia != null)
            {
                try
                {
                    double gainDB = double.Parse(this.textBoxValorGananciadB.Text);
                    if (gainDB == 0.0)
                        ganancia.SetBypass(true);
                    else
                    {
                        ganancia.SetBypass(false);
                        ganancia.Gain_dBV = gainDB;
                    }
                    trackBarGanancia.Value = (int)(gainDB * 1000d);
                }
                catch { }
            }
        }

        private int _dampFX = 0;
        private void checkBoxAmplifDinamica_CheckedChanged(object sender, EventArgs e)
        {
            if (flujo == 0)
                return;

            if (checkBoxAmplifDinamica.Checked)
            {
                _dampFX = Bass.BASS_ChannelSetFX(flujo, BASSFXType.BASS_FX_BFX_DAMP, prioridadModerador);
                Bass.BASS_FXSetParameters(_dampFX, moderador);

            }
            else
            {
                Bass.BASS_ChannelRemoveFX(flujo, _dampFX);
                _dampFX = 0;
            }
        }

        private void trackBarGanancia_ValueChanged_1(object sender, EventArgs e)
        {
            if (ganancia != null)
                this.textBoxValorGananciadB.Text = Convert.ToString(trackBarGanancia.Value / 1000d);
            buttonEstablecerGanancia_Click(this, EventArgs.Empty);
        }
    }
}
